//
//  DrawGLKView.m
//  TQLSmartPen
//
//  Created by tql on 2017/10/20.
//  Copyright © 2017年 tqlZj. All rights reserved.
//

#import "DrawGLKView.h"
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>

#define  MAXNUM_VERTECES 1000000
static GLKVector4 strokeLineColor = { 0, 0, 0, 1};
static float clearColor[4] = { 1, 1, 1, 0};

// Vertex structure containing 3D point and color
struct DrawGLKPoint {
    GLKVector3        vertex;
    GLKVector4        color;
};
typedef struct DrawGLKPoint DrawGLKPoint;
// Maximum verteces in stroke
static const int maxLength = MAXNUM_VERTECES;

// Append vertex to array buffer
static inline void addVertex(uint *dotLength, DrawGLKPoint vertex) {
    if ((*dotLength) >= maxLength) {
        return;
    }
    GLvoid *data = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
    memcpy(data + sizeof(DrawGLKPoint) * (*dotLength), &vertex, sizeof(DrawGLKPoint));
    glUnmapBufferOES(GL_ARRAY_BUFFER);
    (*dotLength)++;
}
// 绘制贝塞尔曲线
CGPoint DrawBezierToCurvl(CGPoint startPoint, CGPoint controlPoint1, CGPoint controlPoint2, CGPoint endPoint,double t) {
    
    double a1 = pow((1 - t), 3);
    double a2 = pow((1 - t), 2) * 3 * t;
    double a3 = 3 * t*t*(1 - t);
    double a4 = t*t*t;
    
    return (CGPoint) {
        a1*startPoint.x + a2*controlPoint1.x + a3*controlPoint2.x + a4*endPoint.x,
        a1*startPoint.y + a2*controlPoint1.y + a3*controlPoint2.y + a4*endPoint.y
    };
}

// Find perpendicular vector from two other vectors to compute triangle strip around line
static GLKVector3 perpendicular(DrawGLKPoint p1, DrawGLKPoint p2) {
    
    GLKVector3 ret;
    ret.x = p2.vertex.y - p1.vertex.y;
    ret.y = -1 * (p2.vertex.x - p1.vertex.x);
    ret.z = 0;
    return ret;
}
static DrawGLKPoint ViewPointToGL(CGPoint viewPoint, CGRect bounds, GLKVector4 color) {
    
    return (DrawGLKPoint) {
        {
            (viewPoint.x / bounds.size.width * 2.0 - 1),
            ((viewPoint.y / bounds.size.height) * 2.0 - 1) * -1,
            0
        },
        color
    };
}
@interface DrawGLKView ()
{
    float g_x0, g_x1, g_x2, g_x3;
    float g_y0, g_y1, g_y2, g_y3;
    float g_p0, g_p1, g_p2, g_p3;
    float g_vx01, g_vy01, g_n_x0, g_n_y0;
    float g_vx21, g_vy21;
    float g_norm;
    float g_n_x2, g_n_y2;
    int gPIndex;
    
    // OpenGL state
    EAGLContext *context;
    GLKBaseEffect *effect;
    
    GLuint vertexArray;
    GLuint vertexBuffer;
    
    // Array of verteces, with current length
    DrawGLKPoint LineVertexData[maxLength];
    uint length;
    
    // Width of line at current and previous vertex
    float penThickness;
    float previousThickness;
    
    // Previous points for quadratic bezier computations
    CGPoint previousPoint;
    DrawGLKPoint previousVertex;
    DrawGLKPoint currentVelocity;
    CAEAGLLayer *eaglLayer;
    float verIndex;
}
@end

@implementation DrawGLKView

#pragma mark - Draw Method

- (void)commonInit {
    
//    CAEAGLLayer *eaglLabter = (CAEAGLLayer *)self.layer;
//    eaglLabter.contentsScale = 4.0f;
//    eaglLabter.contentsGravity = kCAGravityResize;
    // 指定OpenGL 渲染 API 的版本，目前都使用 OpenGL ES 2.0
    context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; //当前上下文
    if (context) {
        time(NULL);
        self.backgroundColor = [UIColor clearColor];
        self.opaque = YES; //不透明度,无需quartz处理透明度.
        // Set the view's scale factor as you wish
        self.contentScaleFactor = [[UIScreen mainScreen] scale];
        self.context = context;
        self.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
        self.enableSetNeedsDisplay = YES;
        //self.drawableMultisample = GLKViewDrawableMultisample4X;
        self.drawableDepthFormat = GLKViewDrawableDepthFormat24;//模板渲染格式
        self.drawableStencilFormat= GLKViewDrawableStencilFormat8;
        // Turn on antialiasing
         self.drawableMultisample = GLKViewDrawableMultisample4X;//多重采样反走样
        [self setupGL];
        
    } else [NSException raise:@"NSOpenGLES2ContextException" format:@"Failed to create OpenGL ES2 context"];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) [self commonInit];
    return self;
}

- (id)initWithFrame:(CGRect)frame context:(EAGLContext *)ctx {
    if (self = [super initWithFrame:frame context:ctx]) [self commonInit];
    return self;
}
- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) [self commonInit];
    return self;
}

- (void)dealloc {
    [self tearDownGL];
    
    if ([EAGLContext currentContext] == context) {
        [EAGLContext setCurrentContext:nil];
    }
    context = nil;
}

- (void)drawRect:(CGRect)rect {
    
    glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
    glClear(GL_COLOR_BUFFER_BIT);

    [effect prepareToDraw];
    // Drawing of signature lines
    if (length > 2) {
        glBindVertexArrayOES(vertexArray);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, length);
        glBlendColor(0, 0, 0, 1);
    }}

- (void)erase {
    
    length = 0;
   // dotsLength = 0;
    self.hasDraw = NO;
    [self setNeedsDisplay];
}

- (UIImage *)drewImage {
    if (!self.hasDraw)
        return nil;
    UIImage *screenshot = [self snapshot];
    return screenshot;
}
- (void)setStrokeColor:(UIColor *)strokeColor {
    _strokeColor = strokeColor;
    [self updateStrokeColor];
}

#pragma mark - Private
- (void)updateStrokeColor {

    CGFloat red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0, white = 0.0;
    if (self.strokeColor && [self.strokeColor getRed:&red green:&green blue:&blue alpha:&alpha]) {
        strokeLineColor = GLKVector4Make(red,green,blue,alpha);
    } else if ( self.strokeColor && [self.strokeColor getWhite:&white alpha:&alpha]) {
        strokeLineColor = GLKVector4Make(white,white,white,alpha);
    } else strokeLineColor = GLKVector4Make(0.0,0.0,0.0,1.0);;
}
- (void)setBackgroundColor:(UIColor *)backgroundColor {
    
    [super setBackgroundColor:backgroundColor];
    CGFloat red, green, blue, alpha, white;
    if ([backgroundColor getRed:&red green:&green blue:&blue alpha:&alpha]) {
        clearColor[0] = red;
        clearColor[1] = green;
        clearColor[2] = blue;
    } else if ([backgroundColor getWhite:&white alpha:&alpha]) {
        clearColor[0] = white;
        clearColor[1] = white;
        clearColor[2] = white;
    }
}

- (void)bindShaderAttributes {
    
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(DrawGLKPoint), 0);
    glEnableVertexAttribArray(GLKVertexAttribColor);
    glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (char *)16);
}

- (void)setupGL {
    [EAGLContext setCurrentContext:context];//设置为当前上下文
    effect = [[GLKBaseEffect alloc] init];
    
    [self updateStrokeColor];
    glDisable(GL_DEPTH_TEST);
    //  Lines
    glGenVertexArraysOES(1, &vertexArray);
    glBindVertexArrayOES(vertexArray);
    
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    
    glBufferData(GL_ARRAY_BUFFER, sizeof(LineVertexData), LineVertexData, GL_DYNAMIC_DRAW);
    [self bindShaderAttributes];
    
    // Perspective
    GLKMatrix4 ortho = GLKMatrix4MakeOrtho(-1, 1, -1, 1, 0.1f, 2.0f);
    effect.transform.projectionMatrix = ortho;
    
    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -1.0f);
    effect.transform.modelviewMatrix = modelViewMatrix;
    
    length = 0;
    penThickness = 0.03;
    previousPoint = CGPointMake(-1, -1);
}

- (void)addTriangleStripPointsForPrevious:(DrawGLKPoint)previousPoint next:(DrawGLKPoint)nextPoint {
    
    float toTravel = penThickness / 2.0;
    
    for (int i = 0; i < 2; i++) {
        
        GLKVector3 perPoint = perpendicular(previousPoint, nextPoint);
        GLKVector3 nextPointV = nextPoint.vertex;
        GLKVector3 ref = GLKVector3Add(nextPointV, perPoint);
        
        float distance = GLKVector3Distance(nextPointV, ref);
        float difX = nextPointV.x - ref.x;
        float difY = nextPointV.y - ref.y;
        float ratio = - 1.0 * (toTravel / distance);
        difX = difX * ratio/self.bounds.size.width;
        difY = difY * ratio/self.bounds.size.height;
        
        DrawGLKPoint stripPoint = {
            {nextPointV.x + difX, nextPointV.y + difY, 0.0},
            strokeLineColor
        };
        addVertex(&length, stripPoint);
        toTravel *= -1;
    }
}
- (void)startWithScale:(float)scale
              offsetX:(float)offsetX
              offsetY:(float)offsetY
             penWidth:(int)penWidth
                    x:(float)pointX
                    y:(float)pointY
                force:(int)force
{
    gPIndex = 0;
    g_x0 = pointX * scale + offsetX - 2.0f;   // x
    g_y0 = pointY * scale + offsetY;          // y
    //g_p0 = fmax(penWidth * 0.5 , penWidth * 13 * force / 1023.0) * scale;   //线宽
    g_p0 = [self getPenWidth:penWidth pressValue:force];
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

    CGPoint startPoint = CGPointMake(g_x0, g_y0);

    float newThickness = g_p0;
    penThickness = newThickness;
    previousPoint = startPoint;
    DrawGLKPoint startVertex = ViewPointToGL(startPoint, self.bounds, strokeLineColor);
    previousVertex = startVertex;
    //addVertex(&length, startVertex);
   // addVertex(&length, startVertex);
   [self addTriangleStripPointsForPrevious:previousVertex next:startVertex];
    self.hasDraw = YES;

    [self setNeedsDisplay];
}

- (void)moveWithScale:(float)scale
             offsetX:(float)offsetX
             offsetY:(float)offsetY
            penWidth:(int)penWidth
                   x:(float)pointX
                   y:(float)pointY
               force:(int)force
{

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

    if (gPIndex == 0) {

        g_x1 = pointX * scale + offsetX - 2.0f;   // x
        g_y1 = pointY * scale + offsetY;          // y
        //g_p0 = fmax(1, penWidth * 3 * (force/2-220) / 1023) * scale;
       // g_p1 = fmax(penWidth * 0.5, penWidth * 13 * force / 1023.0) * scale;   //线宽
        g_p1 = [self getPenWidth:penWidth pressValue:force];
        g_vx01 = g_x1 - g_x0;
        g_vy01 = g_y1 - g_y0;
        // instead of dividing tangent/norm by two, we multiply norm by 2
        g_norm = sqrtf(g_vx01 * g_vx01 + g_vy01 * g_vy01 + 0.0001f) * 2;
        g_vx01 = g_vx01 / g_norm * g_p0;
        g_vy01 = g_vy01 / g_norm * g_p0;
        g_n_x0 = g_vy01;
        g_n_y0 = -g_vx01;

        CGPoint l = CGPointMake(g_x1, g_y1);
        float newThickness = g_p1;
        penThickness = newThickness;

        DrawGLKPoint v1 = ViewPointToGL(l, self.bounds, strokeLineColor);
        //
        // addVertex(&length, v1);
        //
        [self addTriangleStripPointsForPrevious:previousVertex next:v1];
        previousVertex = v1;
       // addVertex(&length, v1);
        //
        previousPoint = l;
        [self setNeedsDisplay];
        gPIndex+=1;
        return;
    }
    if (gPIndex >= 1 && gPIndex < 10000) {

        g_x3 = pointX * scale + offsetX - 2.0f;
        g_y3 = pointY * scale + offsetY;

        g_x2 = (g_x1 + g_x3) / 2;
        g_y2 = (g_y1 + g_y3) / 2;
        g_p2 = (g_p1 + g_p3) / 2;
        //g_p3 = fmax(penWidth * 0.5, penWidth * 13 * force / 1023.0) * scale;
         g_p3 = [self getPenWidth:penWidth pressValue:force];
        g_vx21 = g_x1 - g_x2;
        g_vy21 = g_y1 - g_y2;
        g_norm = sqrtf(g_vx21 * g_vx21 + g_vy21 * g_vy21 + 0.000001f) * 2;

        g_vx21 = g_vx21 / g_norm * g_p2;
        g_vy21 = g_vy21 / g_norm * g_p2;

        g_n_x2 = -g_vy21;
        g_n_y2 = g_vx21;

        //CGPoint startPoint = (CGPoint){g_x0 + g_n_x0, g_y0 + g_n_y0};
        CGPoint startPoint =  CGPointMake(g_x3, g_y3);
        // The + boundary of the stroke
        CGPoint bouControlPoint1 = (CGPoint){g_x1 + g_n_x0,  g_y1 + g_n_y0};
        CGPoint bouControlPoint2 = (CGPoint){g_x1 + g_n_x2, g_y1 + g_n_y2};
        CGPoint bouEndPoint= (CGPoint){g_x2 + g_n_x2, g_y2 + g_n_y2};

        // round out the cap
        CGPoint capControlPoint1 = (CGPoint){g_x2 + g_n_x2 - g_vx21, g_y2 + g_n_y2 - g_vy21};
        CGPoint capControlPoint2 = (CGPoint){g_x2 - g_n_x2 - g_vx21, g_y2 - g_n_y2 - g_vy21};
        CGPoint capEndPoint = (CGPoint){g_x2 - g_n_x2, g_y2 - g_n_y2};

        // THe - boundary of the stroke
        CGPoint reverseBouControlPoint1= (CGPoint){g_x1 - g_n_x2, g_y1 - g_n_y2};
        CGPoint reverseBouControlPoint2  = (CGPoint){g_x1 - g_n_x0, g_y1 - g_n_y0};
        CGPoint reverseBouEndPoint = (CGPoint){g_x0 - g_n_x0, g_y0 - g_n_y0};


        // round out the other cap
        CGPoint otherCapControlPoint1 = (CGPoint){g_x0 - g_n_x0 - g_vx01, g_y0 - g_n_y0 - g_vy01};
        CGPoint otherCapControlPoint2 = (CGPoint){g_x0 + g_n_x0 - g_vx01, g_y0 + g_n_y0 - g_vy01};
        CGPoint otherCapEndPoint = (CGPoint){g_x0 + g_n_x0, g_y0 + g_n_y0};

        float newThickness = g_p3;
        penThickness = newThickness;
        for (int i = 0; i < 2; i++) {
            //float newThickness = g_p0 + (g_p3 - g_p0)*i/4;
            // penThickness = newThickness;
            CGPoint bouQuadPoint = DrawBezierToCurvl(startPoint,bouControlPoint1, bouControlPoint2,bouEndPoint,i/2);
            DrawGLKPoint bouVertex = ViewPointToGL(bouQuadPoint, self.bounds, strokeLineColor);
            [self addTriangleStripPointsForPrevious:previousVertex next:bouVertex];
        
            CGPoint capQuadPoint = DrawBezierToCurvl(startPoint,capControlPoint1, capControlPoint2,capEndPoint,i/2);
            DrawGLKPoint capVertex = ViewPointToGL(capQuadPoint, self.bounds, strokeLineColor);
            [self addTriangleStripPointsForPrevious:previousVertex next:capVertex];
        
            CGPoint reverseBouQuadPoint = DrawBezierToCurvl(startPoint,reverseBouControlPoint1, reverseBouControlPoint2,reverseBouEndPoint,i/2);
            DrawGLKPoint reverseBouVertex = ViewPointToGL(reverseBouQuadPoint, self.bounds, strokeLineColor);
            [self addTriangleStripPointsForPrevious:previousVertex next:reverseBouVertex];
        
            CGPoint otherCapQuadPoint = DrawBezierToCurvl(startPoint,otherCapControlPoint1, otherCapControlPoint2,otherCapEndPoint,i/2);
            DrawGLKPoint otherCapVertex = ViewPointToGL(otherCapQuadPoint, self.bounds, strokeLineColor);
            [self addTriangleStripPointsForPrevious:previousVertex next:otherCapVertex];
       }

       // CGPoint otherCapQuadPoint = DrawBezierToCurvl(startPoint,otherCapControlPoint1, otherCapControlPoint2,otherCapEndPoint,0);
       // DrawGLKPoint  otherCapVertex = ViewPointToGL(otherCapQuadPoint, self.bounds, strokeLineColor);
       // [self addTriangleStripPointsForPrevious:previousVertex next:otherCapVertex];
        newThickness = g_p3;
        penThickness = newThickness;
        CGPoint endPoint =  CGPointMake(g_x3, g_y3);
        DrawGLKPoint vertex = ViewPointToGL(endPoint, self.bounds, strokeLineColor);
       [self addTriangleStripPointsForPrevious:previousVertex next:vertex];
        previousVertex = vertex;
        previousThickness = penThickness;
        previousPoint = endPoint;
        [self setNeedsDisplay];

        g_x0 = g_x2;
        g_y0 = g_y2;

        g_x1 = g_x3;
        g_y1 = g_y3;

        g_p0 = g_p2;
        g_p1 = g_p3;

        g_vx01 = -g_vx21;
        g_vy01 = -g_vy21;

        g_n_x0 = g_n_x2;
        g_n_y0 = g_n_y2;
        gPIndex+=1;

        return;
    }
}


- (void)end {
    
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    CGPoint point = previousPoint;
    float newThickness = g_p3;
    penThickness = newThickness;
    DrawGLKPoint vertex = ViewPointToGL(point, self.bounds, strokeLineColor);
    addVertex(&length, vertex);
    previousVertex = vertex;
    addVertex(&length, vertex);
    [self setNeedsDisplay];
    previousPoint = CGPointMake(0, 0);
}
- (void)tearDownGL {
    
    glDeleteVertexArraysOES(1, &vertexArray);
    glDeleteBuffers(1, &vertexBuffer);
    effect = nil;
}


#pragma mark -private funtion
-(CGFloat)getPenWidth:(CGFloat)penWidth pressValue:(int)pointZ
{
    CGFloat mPenWidth = 1;
    if (penWidth == 1)
    {
        if (pointZ >= 1 && pointZ <= 70){
            mPenWidth = (float) 1;
        }else if (pointZ >70 && pointZ <= 120){
            mPenWidth = (float) 1.5;
        }else if (pointZ >120 && pointZ <= 170){
            mPenWidth = (float) 2;
        }else if (pointZ >170 && pointZ <= 210){
            mPenWidth = (float) 2.5;
        }
        else if (pointZ >210 )
        {
            mPenWidth = (float) 3;
        }
    }else if (penWidth == 2)
    {
        if (pointZ >= 0 && pointZ <= 30){
            mPenWidth = (float) 1.5;
        }else if (pointZ >30 && pointZ <= 80){
            mPenWidth = (float) 2;
        }else if (pointZ >80 && pointZ <= 110){
            mPenWidth = (float) 3;
        }else if (pointZ >110 && pointZ <= 170){
            mPenWidth = (float) 4;
        } else if (pointZ >170 && pointZ <= 190){
            mPenWidth = (float) 4.5;
        }else if (pointZ >190 && pointZ <= 210){
            mPenWidth = (float) 5;
        }
        
        else if (pointZ >210 ){
            mPenWidth = (float) 5.5;
        }
    }else if (penWidth == 3)
    {
        if (pointZ >= 0 && pointZ <= 30){
            mPenWidth = (float) 3;
        }else if (pointZ >30 && pointZ <= 80){
            mPenWidth = (float) 4;
        }else if (pointZ >80 && pointZ <= 110){
            mPenWidth = (float) 5;
        }else if (pointZ >110 && pointZ <= 170){
            mPenWidth = (float) 6;
        } else if (pointZ >170 && pointZ <= 190){
            mPenWidth = (float) 6.5;
        }else if (pointZ >190 && pointZ <= 210){
            mPenWidth = (float) 7;
        }
        
        else if (pointZ >210 )
        {
            mPenWidth = (float) 7.5;
        }
    }else if (penWidth == 4)
    {
        if (pointZ >= 0 && pointZ <= 30){
            mPenWidth = (float) 4;
        }else if (pointZ >30 && pointZ <= 40){
            mPenWidth = (float) 5;
        }else if (pointZ >40 && pointZ <= 50){
            mPenWidth = (float) 6;
        }else if (pointZ >50 && pointZ <= 70){
            mPenWidth = (float) 7;
        } else if (pointZ >70 && pointZ <= 90){
            mPenWidth = (float) 8;
        }else if (pointZ >90 && pointZ <= 110){
            mPenWidth = (float) 9;
        }
        else if (pointZ >110 && pointZ <= 170){
            mPenWidth = (float) 10;
        }else if (pointZ >170 && pointZ <= 190){
            mPenWidth = (float) 10.5;
        }else if (pointZ >190 && pointZ <= 210){
            mPenWidth = (float) 11;
        }
        else if (pointZ >210 )
        {
            mPenWidth = (float) 11.5;
        }
    }else if (penWidth == 5)
    {
        if (pointZ >= 0 && pointZ <= 30){
            mPenWidth = (float) 3;
        }else if (pointZ >30 && pointZ <= 40){
            mPenWidth = (float) 5;
        }else if (pointZ >40 && pointZ <= 50){
            mPenWidth = (float) 7;
        }else if (pointZ >50 && pointZ <= 70){
            mPenWidth = (float) 8;
        } else if (pointZ >70 && pointZ <= 90){
            mPenWidth = (float) 9;
        }else if (pointZ >90 && pointZ <= 110){
            mPenWidth = (float) 10;
        }
        else if (pointZ >110 && pointZ <= 170){
            mPenWidth = (float) 11;
        }else if (pointZ >170 && pointZ <= 190){
            mPenWidth = (float) 11.5;
        }else if (pointZ >190 && pointZ <= 210){
            mPenWidth = (float) 12;
        }
        else if (pointZ >210 )
        {
            mPenWidth = (float) 12.5;
        }
    }
    else if (penWidth == 6)
    {
        if (pointZ >= 0 && pointZ <= 30){
            mPenWidth = (float) 4;
        }else if (pointZ >30 && pointZ <= 40){
            mPenWidth = (float) 6;
        }else if (pointZ >40 && pointZ <= 50){
            mPenWidth = (float) 8;
        }else if (pointZ >50 && pointZ <= 70){
            mPenWidth = (float) 9;
        } else if (pointZ >70 && pointZ <= 90){
            mPenWidth = (float) 10;
        }else if (pointZ >90 && pointZ <= 110){
            mPenWidth = (float) 11;
        }
        else if (pointZ >110 && pointZ <= 170){
            mPenWidth = (float) 12;
        }else if (pointZ >170 && pointZ <= 190){
            mPenWidth = (float) 12.5;
        }else if (pointZ >190 && pointZ <= 210){
            mPenWidth = (float) 13;
        }
        else if (pointZ >210 )
        {
            mPenWidth = (float) 13.5;
        }
    }
    else
    {
        if (pointZ >= 0 && pointZ <= 30){
            mPenWidth = (float) 6;
        }else if (pointZ >30 && pointZ <= 40){
            mPenWidth = (float) 7;
        }else if (pointZ >40 && pointZ <= 50){
            mPenWidth = (float) 8;
        }else if (pointZ >50 && pointZ <= 70){
            mPenWidth = (float) 9;
        } else if (pointZ >70 && pointZ <= 90){
            mPenWidth = (float) 10;
        }else if (pointZ >90 && pointZ <= 110){
            mPenWidth = (float) 11;
        }
        else if (pointZ >110 && pointZ <= 170){
            mPenWidth = (float) 12;
        }else if (pointZ >170 && pointZ <= 190){
            mPenWidth = (float) 12.5;
        }else if (pointZ >190 && pointZ <= 210){
            mPenWidth = (float) 13;
        }
        else if (pointZ >210 ){
            mPenWidth = (float) 13.5;
        }
    }
    return mPenWidth;
}

@end
